package com.example.excel_db.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.example.excel_db.entity.ExcelImportError;
import com.example.excel_db.entity.ExcelImportTask;
import com.example.excel_db.entity.ExcelTemplate;
import com.example.excel_db.entity.ExcelTemplateField;
import com.example.excel_db.repository.ExcelImportErrorRepository;
import com.example.excel_db.repository.ExcelImportTaskRepository;
import com.example.excel_db.repository.ExcelTemplateFieldRepository;
import com.example.excel_db.validator.ExcelDataValidator;
import com.example.excel_db.validator.ExcelDataValidatorFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 默认Excel数据处理器实现
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DefaultExcelDataHandler implements ExcelDataHandler {

    private final ExcelTemplateFieldRepository fieldRepository;
    private final ExcelImportTaskRepository taskRepository;
    private final ExcelImportErrorRepository errorRepository;
    private final ExcelDataValidatorFactory validatorFactory;

    @Value("${excel.import.batch-size:1000}")
    private int batchSize;

    @Override
    public void readExcel(ExcelTemplate template, MultipartFile file, ExcelImportTask task) {
        // 获取模板字段
        List<ExcelTemplateField> fields = fieldRepository.findByTemplateOrderByOrderNumAsc(template);
        if (fields.isEmpty()) {
            task.setStatus(ExcelImportTask.TaskStatus.FAILED);
            task.setErrorMessage("模板没有定义字段");
            taskRepository.save(task);
            return;
        }

        // 获取校验器
        ExcelDataValidator validator = validatorFactory.getValidator(template);

        // 创建字段映射（Excel列名 -> 字段名）
        Map<String, String> columnFieldMap = fields.stream()
                .collect(Collectors.toMap(
                        ExcelTemplateField::getFieldColumn,
                        ExcelTemplateField::getFieldName,
                        (v1, v2) -> v1
                ));

        // 更新任务状态为处理中
        task.setStatus(ExcelImportTask.TaskStatus.PROCESSING);
        taskRepository.save(task);

        // 批量处理数据
        final List<Map<String, Object>> batchData = new ArrayList<>(batchSize);
        final AtomicInteger totalRows = new AtomicInteger(0);
        final AtomicInteger processedRows = new AtomicInteger(0);
        final AtomicInteger successRows = new AtomicInteger(0);
        final AtomicInteger failedRows = new AtomicInteger(0);

        try {
            EasyExcel.read(file.getInputStream(), new AnalysisEventListener<Map<String, Object>>() {
                @Override
                public void invoke(Map<String, Object> data, AnalysisContext context) {
                    int rowIndex = context.readRowHolder().getRowIndex();
                    
                    // 跳过表头行
                    if (rowIndex == 0) {
                        return;
                    }

                    totalRows.incrementAndGet();

                    // 转换列名为字段名
                    Map<String, Object> rowData = new HashMap<>();
                    for (Map.Entry<String, Object> entry : data.entrySet()) {
                        String columnName = entry.getKey();
                        // 处理带有"（必填）"等后缀的列名
                        String cleanColumnName = columnName;
                        if (columnName.contains("（")) {
                            cleanColumnName = columnName.substring(0, columnName.indexOf("（"));
                        }
                        
                        String fieldName = columnFieldMap.get(cleanColumnName);
                        if (fieldName != null) {
                            rowData.put(fieldName, entry.getValue());
                        }
                    }

                    // 添加到批处理数据
                    batchData.add(rowData);

                    // 达到批处理大小时处理数据
                    if (batchData.size() >= batchSize) {
                        processBatch(template, batchData, task, validator, processedRows, successRows, failedRows);
                        batchData.clear();
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    // 处理剩余数据
                    if (!batchData.isEmpty()) {
                        processBatch(template, batchData, task, validator, processedRows, successRows, failedRows);
                        batchData.clear();
                    }

                    // 更新任务状态
                    task.setTotalRows(totalRows.get());
                    task.setProcessedRows(processedRows.get());
                    task.setSuccessRows(successRows.get());
                    task.setFailedRows(failedRows.get());
                    
                    if (failedRows.get() > 0) {
                        task.setStatus(ExcelImportTask.TaskStatus.FAILED);
                        task.setErrorMessage("导入过程中有" + failedRows.get() + "行数据校验失败");
                    } else {
                        task.setStatus(ExcelImportTask.TaskStatus.COMPLETED);
                    }
                    
                    taskRepository.save(task);
                }
            }).sheet().doRead();
        } catch (Exception e) {
            log.error("读取Excel文件失败", e);
            task.setStatus(ExcelImportTask.TaskStatus.FAILED);
            task.setErrorMessage("读取Excel文件失败: " + e.getMessage());
            taskRepository.save(task);
        }
    }

    /**
     * 处理批量数据
     */
    private void processBatch(ExcelTemplate template, List<Map<String, Object>> dataList, 
                             ExcelImportTask task, ExcelDataValidator validator,
                             AtomicInteger processedRows, AtomicInteger successRows, AtomicInteger failedRows) {
        // 校验数据
        Map<Integer, List<String>> errorMap = validator.validateBatch(dataList);
        
        // 记录错误信息
        if (!errorMap.isEmpty()) {
            List<ExcelImportError> errors = new ArrayList<>();
            for (Map.Entry<Integer, List<String>> entry : errorMap.entrySet()) {
                int rowIndex = entry.getKey();
                List<String> errorMessages = entry.getValue();
                
                ExcelImportError error = new ExcelImportError();
                error.setTask(task);
                error.setRowNum(rowIndex + 1); // 转换为1-based索引
                error.setErrorMessage(String.join("; ", errorMessages));
                errors.add(error);
                
                failedRows.incrementAndGet();
            }
            
            if (!errors.isEmpty()) {
                errorRepository.saveAll(errors);
            }
        }
        
        // 处理有效数据
        List<Map<String, Object>> validData = new ArrayList<>();
        for (int i = 0; i < dataList.size(); i++) {
            if (!errorMap.containsKey(i)) {
                validData.add(dataList.get(i));
                successRows.incrementAndGet();
            }
        }
        
        // 处理有效数据
        if (!validData.isEmpty()) {
            processData(template, validData, task);
        }
        
        // 更新处理进度
        processedRows.addAndGet(dataList.size());
        task.setProcessedRows(processedRows.get());
        task.setSuccessRows(successRows.get());
        task.setFailedRows(failedRows.get());
        taskRepository.save(task);
    }

    @Override
    public byte[] writeExcel(ExcelTemplate template, List<Map<String, Object>> dataList) {
        // 获取模板字段
        List<ExcelTemplateField> fields = fieldRepository.findByTemplateOrderByOrderNumAsc(template);
        if (fields.isEmpty()) {
            throw new IllegalStateException("模板没有定义字段");
        }

        // 准备表头数据
        List<List<String>> headList = new ArrayList<>();
        for (ExcelTemplateField field : fields) {
            List<String> head = new ArrayList<>();
            head.add(field.getFieldColumn() + (field.isRequired() ? "（必填）" : ""));
            headList.add(head);
        }

        // 准备数据列表
        List<List<Object>> rows = new ArrayList<>();
        for (Map<String, Object> data : dataList) {
            List<Object> row = new ArrayList<>();
            for (ExcelTemplateField field : fields) {
                row.add(data.get(field.getFieldName()));
            }
            rows.add(row);
        }

        // 设置表头和内容样式
        WriteCellStyle headStyle = new WriteCellStyle();
        headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        WriteFont headFont = new WriteFont();
        headFont.setBold(true);
        headFont.setFontHeightInPoints((short) 12);
        headStyle.setWriteFont(headFont);
        headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        headStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        WriteCellStyle contentStyle = new WriteCellStyle();
        contentStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(headStyle, contentStyle);

        // 生成Excel文件
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            EasyExcel.write(outputStream)
                    .head(headList)
                    .registerWriteHandler(styleStrategy)
                    .sheet(template.getName())
                    .doWrite(rows);
            return outputStream.toByteArray();
        } catch (Exception e) {
            log.error("生成Excel文件失败", e);
            throw new RuntimeException("生成Excel文件失败", e);
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                log.error("关闭输出流失败", e);
            }
        }
    }

    @Override
    public boolean processData(ExcelTemplate template, List<Map<String, Object>> dataList, ExcelImportTask task) {
        // 这里是数据处理的扩展点，子类可以覆盖此方法实现自定义的数据处理逻辑
        // 例如，将数据保存到数据库或进行其他业务处理
        log.info("处理Excel数据: 模板={}, 数据行数={}", template.getName(), dataList.size());
        return true;
    }
}